-
Notifications
You must be signed in to change notification settings - Fork 599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(storage): Splitting table change log from HummockVersion on CN side #20050
Conversation
…nto li0k/storage_divide_table_change_log
…nto li0k/storage_divide_table_change_log
guard: Arc::new(PinnedVersionGuard::new( | ||
version_id, | ||
self.guard.pinned_version_manager_tx.clone(), | ||
)), | ||
table_change_log: Arc::new(RwLock::new(t)), | ||
version: Arc::new(LocalHummockVersion::from(version)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just want to leave a note here.
This LocalHummockVersion::from
is an addtional HummockVersion
conversion introduced by this PR. However I don't think it will have significant performance implications, as it primarily involves move semantics.
let change_log = { | ||
let table_change_logs = version.table_change_log().read(); | ||
if let Some(change_log) = table_change_logs.get(&options.table_id) { | ||
change_log.filter_epoch(epoch_range).cloned().collect_vec() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cloned() is an additional cost introduced in this PR.
If multiple iter_log are running simultaneously, will the memory usage be substantial?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @wenym1 , suggests that iter_log
is executed less frequently and that this clone is acceptable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In current usage of iter_log
, we only do iter_log on a single epoch, so this vector should be small.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…nto li0k/storage_divide_table_change_log
…nto li0k/storage_divide_table_change_log
interfaces are affected:
cc @wenym1 |
…nto li0k/storage_divide_table_change_log
…nto li0k/storage_divide_table_change_log
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rest LGTM. Thanks for the PR.
let change_log = { | ||
let table_change_logs = version.table_change_log().read(); | ||
if let Some(change_log) = table_change_logs.get(&options.table_id) { | ||
change_log.filter_epoch(epoch_range).cloned().collect_vec() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In current usage of iter_log
, we only do iter_log on a single epoch, so this vector should be small.
.build_sst_delta_infos(version_delta) | ||
.into_iter(), | ||
let mut version_to_apply = pinned_version.version().clone(); | ||
let table_change_log_to_apply = pinned_version.take_change_log(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of take_change_log
, we can have method change_log_write_lock
to return the write lock on the table_change_log
. And then in new_pin_version_with_table_change_log
, we don't have to pass the table_change_log_to_apply
again. We can use the original table_change_log
wrapped by Arc
and simply clone the Arc
.
Besides, it seems that the parameter pinned_version
of the current method is not necessary to take the ownership. We can change to pass &PinnedVersion
, so that the caller can avoid doing clone on it.
…nto li0k/storage_divide_table_change_log
…nto li0k/storage_divide_table_change_log
@@ -476,10 +473,26 @@ impl HummockVersion { | |||
state_table_info_delta: Default::default(), | |||
} | |||
} | |||
|
|||
pub fn split_change_log(mut self) -> (LocalHummockVersion, HashMap<TableId, TableChangeLog>) { | |||
let table_change_log = std::mem::take(&mut self.table_change_log); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here after std::mem::take(&mut self.table_change_log)
, the epochs
in self.table_change_log
becomes empty. But we still need to use the epochs
in LocalHummockVersion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch !!!
…nto li0k/storage_divide_table_change_log
This pull request has been modified. If you want me to regenerate unit test for any of the files related, please find the file in "Files Changed" tab and add a comment |
@wenym1 PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rest LGTM!
let mut change_log = VecDeque::new(); | ||
for item in log.change_log_iter_mut() { | ||
let new_value = EpochNewChangeLogCommon { | ||
new_value: std::mem::take(&mut item.new_value), | ||
old_value: std::mem::take(&mut item.old_value), | ||
epochs: item.epochs.clone(), | ||
}; | ||
|
||
change_log.push_back(new_value); | ||
} | ||
table_change_log | ||
.insert(*table_id, TableChangeLogCommon::new(change_log.into_iter())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut change_log = VecDeque::new(); | |
for item in log.change_log_iter_mut() { | |
let new_value = EpochNewChangeLogCommon { | |
new_value: std::mem::take(&mut item.new_value), | |
old_value: std::mem::take(&mut item.old_value), | |
epochs: item.epochs.clone(), | |
}; | |
change_log.push_back(new_value); | |
} | |
table_change_log | |
.insert(*table_id, TableChangeLogCommon::new(change_log.into_iter())); | |
let change_log_iter = log.change_log_iter_mut().map(|item| { | |
EpochNewChangeLogCommon { | |
new_value: std::mem::take(&mut item.new_value), | |
old_value: std::mem::take(&mut item.old_value), | |
epochs: item.epochs.clone(), | |
} | |
} | |
table_change_log | |
.insert(*table_id, TableChangeLogCommon::new(change_log_iter)); |
…nto li0k/storage_divide_table_change_log
I hereby agree to the terms of the RisingWave Labs, Inc. Contributor License Agreement.
What's changed and what's your intention?
This PR optimize clone behavior on the CN side. Previously, the hummock event handler copied the hummock version every time it applied a delta, and the overhead of cloning could cause performance problems.issues.
risingwave/src/storage/src/hummock/event_handler/hummock_event_handler.rs
Line 529 in 95abcc9
This PR split the table change log from the hummock version to avoid copying all table change logs at each version delta.
Key changes include:
Enhancements to
HummockVersion
andHummockVersionDelta
:L
toHummockVersionCommon
andHummockVersionDeltaCommon
to improve type safety and flexibility. Split table_change_log into separate fields and protect them with RwLock. (src/storage/hummock_sdk/src/version.rs
,src/storage/hummock_sdk/src/compaction_group/hummock_version_ext.rs
)New Methods and Type Changes:
change_log_into_iter
method toTableChangeLogCommon
to allow iteration over change logs. (src/storage/hummock_sdk/src/change_log.rs
)Type Aliases:
HummockVersionCommon
andHummockVersionDeltaCommon
. (src/storage/hummock_sdk/src/time_travel.rs
,src/storage/hummock_sdk/src/version.rs
)Import Adjustments:
src/storage/hummock_sdk/src/compaction_group/hummock_version_ext.rs
,src/storage/hummock_sdk/src/version.rs
,src/storage/src/hummock/event_handler/hummock_event_handler.rs
)Checklist
Documentation
Release note